<template>
  <!-- 画图页面 -->
  <el-dialog title="流程图" :visible.sync="visible" :close-on-click-modal="false" fullscreen @close="handleClose">
    <!-- 创建一个canvas画布 bpmn-js是通过canvas实现绘图的，并设置ref让vue获取到element -->
    <div class="bpmn-container">
      <el-container style="height: 100%;">
        <el-container style="align-items: stretch">
          <el-header style="border-bottom: 1px solid rgb(238,234,234);height: auto; padding: 0; display: flex; justify-content: space-between;">
            <div>
              <!--          <el-tooltip effect="dark" content="新建" placement="bottom">-->
              <!--            <el-button size="mini" icon="el-icon-circle-plus" @click="newDiagram" />-->
              <!--          </el-tooltip>-->
              <el-button-group>
                <el-tooltip effect="dark" content="自适应屏幕" placement="bottom">
                  <el-button size="mini" icon="el-icon-rank" @click="fitViewport" />
                </el-tooltip>
                <el-tooltip effect="dark" content="放大" placement="bottom">
                  <el-button size="mini" icon="el-icon-zoom-in" @click="zoomViewport(true)" />
                </el-tooltip>
                <el-tooltip effect="dark" content="缩小" placement="bottom">
                  <el-button size="mini" icon="el-icon-zoom-out" @click="zoomViewport(false)" />
                </el-tooltip>
                <el-tooltip effect="dark" content="撤销" placement="bottom">
                  <el-button size="mini" icon="el-icon-arrow-left" @click="modeler.get('commandStack').undo()" />
                </el-tooltip>
                <el-tooltip effect="dark" content="恢复" placement="bottom">
                  <el-button size="mini" icon="el-icon-arrow-right" @click="modeler.get('commandStack').redo()" />
                </el-tooltip>
              </el-button-group>
            </div>
            <div>
              <el-button-group>
                <el-button size="mini" icon="el-icon-download" @click="handleFlowXml(true)">下载xml</el-button>
                <el-button size="mini" icon="el-icon-picture" @click="handleFlowImg(true)">下载svg</el-button>
                <el-button size="mini" type="primary" @click="handleSave()">保存模型</el-button>
              </el-button-group>
            </div>
          </el-header>
          <el-main style="padding: 0;">
            <div ref="canvas" class="bpmn-canvas" />
          </el-main>
        </el-container>
        <!-- 工具栏显示的地方 -->
        <el-aside width="450px" style="min-height: 650px; background-color: #ffffff;">
          <el-container style="width: 100%;">
            <panel v-if="modeler" ref="panel" :modeler="modeler" :users="users" />
          </el-container>
        </el-aside>
      </el-container>
    </div>
  </el-dialog>
</template>

<script>
import BpmnModeler from 'bpmn-js/lib/Modeler'
import Panel from './components/Panel.vue'
// // 汉化
import customTranslate from './components/customTranslate'
// // 引入flowable的节点文件
import flowableModdle from './components/flowable.json'

export default {
  name: 'ModelerDesign',
  components: { Panel },
  // props属性
  props: {
    show: {
      type: Boolean,
      required: true
    },
    xml: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      visible: false,
      canvas: null,
      users: [{ code: 'zhangsan', text: '张三' }, { code: 'lisi', text: '李四' }],
      modeler: null,
      bpmnTemplate: '',
      formData: {}
    }
  },
  // 生命周期 - 创建完成（可以访问当前this实例）
  created() {},
  // 生命周期 - 载入后, Vue 实例挂载到实际的 DOM 操作完成，一般在该过程进行 Ajax 交互
  mounted() {},
  methods: {
    init() {
      this.visible = this.show

      // 需要在Dom初始化完成后再创建Bpmn对象实例
      this.$nextTick(() => {
        this.initModeler()
      })
    },
    // 初始化BpmnModeler对象
    initModeler() {
      // 获取画布 element，ref为“canvas”的dom节点
      this.canvas = this.$refs.canvas
      // 将汉化包装成一个模块
      const customTranslateModule = {
        translate: ['value', customTranslate]
      }
      // 创建Bpmn对象实例
      this.modeler = new BpmnModeler({
        // 设置bpmn的绘图容器为上门获取的画布 element
        container: this.canvas,
        additionalModules: [
          // 汉化模块
          customTranslateModule
        ],
        moddleExtensions: {
          flowable: flowableModdle
        }
      })

      // 初始化流程图
      if (this.xml) {
        console.log('初始化流程图')
        this.handleFlowDiagram(this.xml)
      } else {
        console.log('创建一个空白流程图')
        this.modeler.createDiagram()
      }
    },
    // 新增
    handleCreateNewDiagram() {
      this.handleFlowDiagram(this.bpmnTemplate)
    },
    // 画出流程图
    async handleFlowDiagram(bpmn) {
      bpmn = bpmn.replace(/<!\[CDATA\[(.+?)]]>/g, function(match, str) {
        return str.replace(/</g, '&lt;')
      })
      // 将字符串转换成图显示出来
      try {
        const result = await this.modeler.importXML(bpmn)
        console.log(436666)
        console.log(result)
        // const { warnings } = result
        // this.translatePalette()
        this.fitViewport()
      } catch (err) {
        console.log(err.message, err.warnings)
        this.$message.error('打开模型出错，请确认该模型符合Bpmn2.0规范！')
      }
    },
    // 使流程图能自适应屏幕
    fitViewport() {
      this.zoom = this.modeler.get('canvas').zoom('fit-viewport')
      const bbox = document.querySelector('.bpmn-container .viewport').getBBox()
      const currentViewBox = this.modeler.get('canvas').viewbox()
      const elementMid = {
        x: bbox.x + bbox.width / 2 - 65,
        y: bbox.y + bbox.height / 2
      }
      this.modeler.get('canvas').viewbox({
        x: elementMid.x - currentViewBox.width / 2,
        y: elementMid.y - currentViewBox.height / 2,
        width: currentViewBox.width,
        height: currentViewBox.height
      })
      this.zoom = bbox.width / currentViewBox.width * 1.8
    },
    // 放大缩小
    zoomViewport(zoomIn = true) {
      this.zoom = this.modeler.get('canvas').zoom()
      this.zoom += (zoomIn ? 0.1 : -0.1)
      this.modeler.get('canvas').zoom(this.zoom)
    },
    // 流程xml，根据传参确定是否需要下载
    async handleFlowXml(download = false) {
      try {
        const { xml } = await this.modeler.saveXML({ format: true })
        if (download) {
          this.handleDownloadFile(`${this.handleProcessElement().name}.bpmn20.xml`, xml, 'application/xml')
        }
        return xml
      } catch (err) {
        console.log(err)
      }
    },
    // 流程Image图片，根据传参确定是否需要下载
    async handleFlowImg(download = false) {
      try {
        const { svg } = await this.modeler.saveSVG({ format: true })
        if (download) {
          this.handleDownloadFile(this.handleProcessElement().name, svg, 'image/svg+xml')
        }
        return svg
      } catch (err) {
        console.log(err)
      }
    },
    // 获取流程
    handleProcessElement() {
      const rootElements = this.modeler.getDefinitions().rootElements
      for (let i = 0; i < rootElements.length; i++) {
        if (rootElements[i].$type === 'bpmn:Process') return rootElements[i]
      }
    },
    // 执行下载文件
    handleDownloadFile(filename, data, type) {
      const a = document.createElement('a')
      const url = window.URL.createObjectURL(new Blob([data], { type: type }))
      a.href = url
      a.download = filename
      a.click()
      window.URL.revokeObjectURL(url)
    },
    // 重置表单
    handleRestFormData() {
      this.formData = {
        id: undefined,
        modelerId: undefined,
        modelerKey: undefined,
        modelerName: undefined,
        modelerDesc: undefined,
        modelerCategory: undefined,
        modelerVersion: undefined,
        modelerXml: undefined,
        remark: ''
      }
    },
    // 保存
    async handleSave() {
      const xml = await this.handleFlowXml(false)
      const el = this.handleProcessElement()
      this.formData.modelerKey = el.id
      this.formData.modelerName = el.name
      if (el.documentation && el.documentation.length > 0) {
        this.formData.modelerDesc = el.documentation[0].text
      }
      this.formData.modelerCategory = el.$parent.targetNamespace
      this.formData.modelerXml = xml
      console.log('保存数据：' + JSON.stringify(this.formData))
    },
    // 关闭弹出框
    handleClose() {
      this.visible = false
      this.canvas = null
      this.bpmnTemplate = ''
      // 脱离dom
      // this.modeler.detach()
      // 销毁
      this.modeler.destroy()
      this.modeler = null
    }
  }
}
</script>

<style>
/*左边工具栏以及编辑节点的样式*/
@import "~bpmn-js/dist/assets/diagram-js.css";
@import "~bpmn-js/dist/assets/bpmn-font/css/bpmn.css";
@import "~bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css";
@import "~bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";

.bpmn-container {
  width: 100%;
  height: 100%;
  .canvas {
    width: 100%;
    height: 100%;
  }
}

.bpmn-canvas {
  width: 100% !important;
  //width: calc(100% - 300px);
  height: 90vh;
}

.el-aside {
  margin-right: 3px;
  border-left: solid rgba(246, 241, 241, 0.7);
  border-right: solid rgba(246, 241, 241, 0.7);
  padding: 8px 0;
}

</style>
